/*
 * Copyright zh.weir.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.sina.stock;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.GetMethod;
import com.sina.util.StringUtil;

/**
 * @author <a href="http://www.blogjava.net/zh-weir/" target="_blank">zh.weir的技术博�?/a>
 * </br>
 * </br>
 * <a href="http://weibo.com/1779382071?s=6uyXnP" target="_blank"><img border="0" src="http://service.t.sina.com.cn/widget/qmd/1779382071/9c2d28b9/1.png"/></a>
 * 
 */
public final class SinaStockClient {
	
	private final static String STOCK_URL = "http://hq.sinajs.cn/list=";

    private final static String CHARSET_GBK = "gbk";
    private final static String CHARSET_GB2312 = "gb2312";
    private final static String CHARSET_UTF8 = "UTF-8";

	private final static int CONNECTION_TIMEOUT = 5000;
	private final static int SO_TIMEOUT = 30000;
	
	private HttpClient mHttpClient;
	private static SinaStockClient mInstance;
	
	private SinaStockClient(){
		mHttpClient = new HttpClient();
		mHttpClient.getHttpConnectionManager().getParams().setConnectionTimeout(CONNECTION_TIMEOUT);   
		mHttpClient.getHttpConnectionManager().getParams().setSoTimeout(SO_TIMEOUT);  
	}
	
	/**
	 * @return SinaStockClient
	 */
	public synchronized static SinaStockClient getInstance() {
		if(mInstance != null) {
			return mInstance;
		}
		return new SinaStockClient();
	}
	
	/**
	 * 通过股票代码，获取行情信息�? 
	 * @param stockCodes 
	 * 		股票代码数组。沪市股票代码以"sh+股票代码", 深市股票代码�?sz+股票代码"�?
	 * @return 成功返回List<SinaStockInfo>，失败返回null�?	
	 * @throws java.io.IOException
	 * @throws HttpException 
	 * @throws SinaStockInfo.ParseStockInfoException
	 */
	public List<SinaStockInfo> getStockInfoList(String[] stockCodes) throws HttpException, IOException, SinaStockInfo.ParseStockInfoException {
		String url = STOCK_URL + StringUtil.transferArray2String(stockCodes);
		HttpMethod method = new GetMethod(url);
		int statusCode = mHttpClient.executeMethod(method);
		if(statusCode != HttpStatus.SC_OK) {
			method.releaseConnection();
			return null;
		}
		InputStream is = method.getResponseBodyAsStream();
		InputStreamReader reader = new InputStreamReader(new BufferedInputStream(is), Charset.forName(CHARSET_GBK));
		BufferedReader bReader = new BufferedReader(reader);
		List<SinaStockInfo> list = parseSinaStockInfosFromReader(bReader);
		bReader.close();
		method.releaseConnection();
		return list;
	}

    private List<SinaStockInfo> parseSinaStockInfosFromReader(BufferedReader reader) throws IOException, SinaStockInfo.ParseStockInfoException {
		ArrayList<SinaStockInfo> list = new ArrayList<SinaStockInfo>(10);
		String sourceLine = null;
		while((sourceLine = reader.readLine()) != null) {
			list.add(SinaStockInfo.parseStockInfo(sourceLine));
		}
		return list;
	}
	
	//获取证券信息
	public Map<String,SinaStockInfo> getStockInfoMap(String[] stockCodes) throws IOException, SinaStockInfo.ParseStockInfoException {
		String url = STOCK_URL + StringUtil.transferArray2String(stockCodes);
		HttpMethod method = new GetMethod(url);
		int statusCode = mHttpClient.executeMethod(method);
		if(statusCode != HttpStatus.SC_OK) {
			method.releaseConnection();
			return null;
		}
		InputStream is = method.getResponseBodyAsStream();
		InputStreamReader reader = new InputStreamReader(new BufferedInputStream(is), Charset.forName("gbk"));
		BufferedReader bReader = new BufferedReader(reader);
		
		Map<String,SinaStockInfo> sMap = new HashMap<String,SinaStockInfo>();
		String sourceLine = null;
		int i=0;
		while((sourceLine = bReader.readLine()) != null) {
			sMap.put(stockCodes[i++], SinaStockInfo.parseStockInfo(sourceLine));
		}
		bReader.close();
		method.releaseConnection();
		return sMap;
	}

//    private List<Double> parseStockPricesList(BufferedReader reader) throws IOException, SinaStockInfo.ParseStockInfoException {
//		ArrayList<Double> list = new ArrayList<Double>();
//		String sourceLine = null;
//		while((sourceLine = reader.readLine()) != null) {
//			list.add(SinaStockInfo.parseStockPrice(sourceLine));
//		}
//		return list;
//	}

    public List<Double> getStockPricesList(String[] stockCodes) throws HttpException, IOException, SinaStockInfo.ParseStockInfoException {
		String url = STOCK_URL + StringUtil.transferArray2String(stockCodes);
		HttpMethod method = new GetMethod(url);
		int statusCode = mHttpClient.executeMethod(method);
		if(statusCode != HttpStatus.SC_OK) {
			method.releaseConnection();
			return null;
		}
		InputStream is = method.getResponseBodyAsStream();
		InputStreamReader reader = new InputStreamReader(new BufferedInputStream(is), Charset.forName("gbk"));
		BufferedReader bReader = new BufferedReader(reader);
		ArrayList<Double> list = new ArrayList<Double>();
		String sourceLine = null;
		while((sourceLine = bReader.readLine()) != null) {
			list.add(SinaStockInfo.parseStockPrice(sourceLine));
		}

		bReader.close();
		method.releaseConnection();
		return list;
	}

	public Map<String,Double> getStockPriceMap(String[] stockCodes) throws HttpException, IOException, SinaStockInfo.ParseStockInfoException {
		String url = STOCK_URL + StringUtil.transferArray2String(stockCodes);
		HttpMethod method = new GetMethod(url);
		int statusCode = mHttpClient.executeMethod(method);
		if(statusCode != HttpStatus.SC_OK) {
			method.releaseConnection();
			return null;
		}
		InputStream is = method.getResponseBodyAsStream();
		InputStreamReader reader = new InputStreamReader(new BufferedInputStream(is), Charset.forName("gbk"));
		BufferedReader bReader = new BufferedReader(reader);
		Map<String,Double> sMap = new HashMap<String,Double>();
		String sourceLine = null;
		int i=0;
		while((sourceLine = bReader.readLine()) != null) {
			sMap.put(stockCodes[i++], SinaStockInfo.parseStockPrice(sourceLine));
		}
		
		bReader.close();
		method.releaseConnection();
		return sMap;
	}

    public static void main(String[] args) {
        String[] stockCodes = new String[]{"sz150018","sz150019"};
        SinaStockClient client = SinaStockClient.getInstance();
        List<SinaStockInfo> stockList;
        List<Double> priceList;
        try {
            stockList = client.getStockInfoList(stockCodes);
            for (SinaStockInfo sinaStockInfo : stockList) {
                System.out.println(sinaStockInfo.toString());
            }
            priceList = client.getStockPricesList(stockCodes);
            for (Double aDouble : priceList) {
                System.out.println(aDouble);
            }

        } catch (IOException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        } catch (SinaStockInfo.ParseStockInfoException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        }

    }


}


